home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 May: Tool Chest / Developer CD Series May 1996 (Tool Chest) (Apple Computer) (1996).iso / Sample Code / Standard File Samples / CustomPutSuffix / CustomPutSuffix.c < prev    next >
Encoding:
Text File  |  1995-06-16  |  11.2 KB  |  329 lines  |  [TEXT/MMCC]

  1. //
  2. //    Application:    CustomPutSuffix
  3. //    
  4. //    Description:    This demonstrates a CustomPutDialog with an Save button that checks
  5. //                    to see if several files (with the name filename+suffix) already exist.
  6. //                    a dialog hook procedure is responsible for presenting separate "Replace?" 
  7. //                    dialogs.  When the Save button is hit and, if the user allows the save,
  8. //                    the Save action is map to a Cancel action but the reply is marked as good.
  9. //
  10. //    Programmer:        David Hayward
  11. //                    Developer Technical Support
  12. //                    Apple Computer, Inc.
  13. //
  14. //    Environment:    Metrowerks C version 6, Universal Interfaces 2.0
  15. //
  16. //    History:        5/3/93
  17. //                      first draft
  18. //                    5/12/95
  19. //                      updated project for Metrowerks
  20. //    
  21.  
  22.  
  23. #include <stddef.h>
  24.  
  25. #include <QuickDraw.h>
  26. #include <Memory.h>
  27. #include <Files.h>
  28. #include <Errors.h>
  29. #include <Fonts.h>
  30. #include <Resources.h>
  31. #include <StandardFile.h>
  32. #include <Files.h>
  33. #include <Dialogs.h>
  34. #include <TextUtils.h>
  35.  
  36. #include "InitMac.h"
  37.  
  38.  
  39. /**\
  40. |**| ==============================================================================
  41. |**| DEFINES
  42. |**| ==============================================================================
  43. \**/
  44. #define    outputDlogID        128
  45. #define    outputQuit            1
  46. #define    outputAgain            2
  47.  
  48. #define    replaceDlogID        6045
  49. #define    replaceCancel        1
  50. #define    replaceOK            2
  51.  
  52. #define    SuffixID            128
  53.  
  54.  
  55. /**\
  56. |**| ==============================================================================
  57. |**| TYPEDEFS
  58. |**| ==============================================================================
  59. \**/
  60.  
  61. /*------------------------------------------------------------------------------*\
  62.     myData
  63.  *------------------------------------------------------------------------------*
  64.         the 'myData' structure is passed to CustomPutFile() so that 
  65.         MyDlgHook() can access the list of suffixes and return the results 
  66. \*------------------------------------------------------------------------------*/
  67. typedef struct myData
  68. {
  69.     StandardFileReply        *replyPtr;    /* we also need to pass in the SFR so that */
  70.                                         /* MyDlgHook() knows what user specified in */
  71.                                         /* the CustomPutFile dialog */
  72.     short                    num;        /* the number of entries in the array */
  73.     
  74.     struct
  75.     {                                    /* struct for each suffix to check */
  76.         Str63  suffix;                    /* suffix string to append */
  77.         FSSpec spec;                    /* FSSpec for the file */
  78.         FInfo  info;                    /* returned info and err just in case */
  79.         OSErr  err;                        /* we need this information later */
  80.     }                        files[];    /* variable length array of the above */
  81. } myData, *myDataPtr;
  82.  
  83.  
  84.  
  85. /**\
  86. |**| ==============================================================================
  87. |**| FUNCTION PROTOTYPES
  88. |**| ==============================================================================
  89. \**/
  90. void            AppendStrToStr        ( StringPtr dst, StringPtr src, unsigned char maxDstLen );
  91. void            AppendStrToHdl        ( Handle dst, StringPtr src );
  92. pascal short    MyDlgHook            ( short item, DialogPtr theDialog, void *data );
  93. short            myReplaceAlert        ( myDataPtr dataPtr );
  94. short            outputDlog            ( myDataPtr dataPtr );
  95. void            initializeData        ( myDataPtr *dataPtr, StandardFileReply *replyPtr );
  96. void            main                ( void );
  97.  
  98.  
  99. /*------------------------------------------------------------------------------*\
  100.     AppendStrToStr()
  101.  *------------------------------------------------------------------------------*
  102.         utility function to append one string to another
  103.         this function should be improved to handle errors
  104. \*------------------------------------------------------------------------------*/
  105. void AppendStrToStr ( StringPtr dst, StringPtr src, unsigned char maxDstLen )
  106. {
  107.     short        offset = dst[0]+1;
  108.     short        size   = src[0];
  109.     
  110.     if ( dst[0] + src[0] > maxDstLen)            // make sure were not too big
  111.         size = maxDstLen - dst[0];                // you should return a warning here
  112.     BlockMove( src+1, dst+offset, size);
  113.     dst[0] += size;
  114. }
  115.  
  116.     
  117. /*------------------------------------------------------------------------------*\
  118.     AppendStrToHdl()
  119.  *------------------------------------------------------------------------------*
  120.         utility function to append a string to a handle
  121.         this function should be improved to handle errors
  122. \*------------------------------------------------------------------------------*/
  123. void AppendStrToHdl ( Handle dst, StringPtr src )
  124. {
  125.     short        size = src[0];
  126.     PtrAndHand( src+1, dst, size);
  127. }
  128.  
  129.     
  130. /*------------------------------------------------------------------------------*\
  131.     MyDlgHook()
  132.  *------------------------------------------------------------------------------*
  133.         the dialog hook procedure responsible for presenting my own "Replace?" 
  134.         dialogs when the Save button is hit and, if the user allows the save,
  135.         then map the Save action to a Cancel action but mark the reply as good.
  136. \*------------------------------------------------------------------------------*/
  137. pascal short MyDlgHook ( short item, DialogPtr theDialog, void *data )
  138. {
  139.     long                        refCon;
  140.     short                        r;
  141.  
  142.     refCon = GetWRefCon((WindowPtr)theDialog);            /* get the refCon of the current dialog */
  143.  
  144.     if (refCon == sfMainDialogRefCon)                    /* if its the "Save As…" dialog */
  145.     {
  146.         if (item == sfItemOpenButton)                    /* if user hit Save button */
  147.         {
  148.             r = myReplaceAlert((myDataPtr)data);        /* present my "Replce? dialogs */
  149.             if ( r == replaceCancel )                    /* if user hit a Cancel button */
  150.                 item = sfHookNullEvent;                    /* then do nothing */
  151.             else                                        /* if user hit replace button */
  152.             {                                            /* then user wants to save so...*/
  153.                 item  = sfItemCancelButton;                /* change to Cancel action but */ 
  154.                 ((myDataPtr)data)->replyPtr->sfGood = 1;/* mark reply as good */
  155.             }
  156.         }
  157.     }
  158.     
  159.     return item;
  160. }
  161.  
  162.  
  163. /*------------------------------------------------------------------------------*\
  164.     myReplaceAlert()
  165.  *------------------------------------------------------------------------------*
  166.         this routine, called from MyDlgHook(), presents a "Replce? dialog
  167.         for any filename+suffix that already exist.  If one of these
  168.         dialogs is canceles then this procedure returns 'cancel'
  169. \*------------------------------------------------------------------------------*/
  170. short myReplaceAlert ( myDataPtr dataPtr )
  171. {
  172.     short        i, item;
  173.     OSErr        err;
  174.     FSSpec        spec;
  175.     FInfo        info;
  176.     
  177.     for (i=0; i<dataPtr->num; i++)                        /* loop thru each suffix in dataPtr ... */
  178.     {
  179.         spec = dataPtr->replyPtr->sfFile;                /* spec starts out as the FSSpec (vRefNum, */
  180.                                                         /* parID & name) the user specified in the */
  181.                                                         /* CustomPutFile dialog  */
  182.         
  183.         AppendStrToStr( spec.name,
  184.                         dataPtr->files[i].suffix, 63);    /* append suffix to filename */
  185.  
  186.         err = FSpGetFInfo(&spec, &info);                /* try to get info for this spec */
  187.         
  188.         dataPtr->files[i].spec = spec;                    /* save the spec, info & err for this */
  189.         dataPtr->files[i].info = info;                    /* file in dataPtr just in case we need  */
  190.         dataPtr->files[i].err = err;                    /* this information later */ 
  191.  
  192.         if (err == 0)                                    /* filename+suffix already exists so.. */ 
  193.         {
  194.             ParamText( spec.name, nil, nil, nil);        /* setup param text for "Replace?" alert*/
  195.             item = Alert(replaceDlogID,nil);            /* put up alert */
  196.             if (item == replaceCancel)                    /* if user hit cancel button */
  197.                 return replaceCancel;                    /* then stop and return 'cancel' */
  198.         }
  199.         else if (err == fnfErr)                            /* if filename+suffix doesn't exist */
  200.         {
  201.             /* all you need to do in here is make sure that filename+suffix */
  202.             /* isn't a directory and put up an an alert if it is */
  203.         }
  204.         else                                            /* if some other err was returned ... */
  205.         {
  206.             /* here you need to handle other errors such as 'badNamErr' */
  207.         }
  208.     }
  209.     return replaceOK;
  210. }
  211.  
  212.  
  213. /*------------------------------------------------------------------------------*\
  214.     outputDlog()
  215.  *------------------------------------------------------------------------------*
  216.         output vital stats of the StandardFileReply to an dialog box
  217. \*------------------------------------------------------------------------------*/
  218. short outputDlog ( myDataPtr dataPtr )
  219. {
  220.     DialogPtr    dlg;
  221.     Rect        iRect;
  222.     Handle        iHndl;
  223.     short        iType;
  224.     short        item;
  225.     short        i;
  226.     
  227.     dlg = GetNewDialog(outputDlogID, nil, (WindowPtr)-1);
  228.     
  229.     GetDItem( dlg, 3, &iType, &iHndl, &iRect );            /* get handle to static text field */
  230.  
  231.     if (dataPtr->replyPtr->sfGood == 0)                    /* if reply is not good */
  232.         AppendStrToHdl (iHndl, "\pUser canceled.");
  233.     else
  234.     {
  235.         for (i=0; i<dataPtr->num; i++)                    /* loop thru each suffix in dataPtr ... */
  236.         {
  237.             AppendStrToHdl( iHndl, dataPtr->files[i].spec.name);     /* append filename */
  238.             
  239.             if ( dataPtr->files[i].err == 0)            /* if filename+suffix already exists */
  240.                 AppendStrToHdl( iHndl, "\p (exists)");    /* append (exists) */
  241.             else if ( dataPtr->files[i].err != fnfErr)
  242.                 AppendStrToHdl( iHndl, "\p (error)");    /* append (error) */
  243.     
  244.             AppendStrToHdl( iHndl, "\p\r");                /* append CR */
  245.         }
  246.     }
  247.     
  248.     ShowWindow( dlg );
  249.     
  250.     do
  251.     {
  252.         ModalDialog(0,&item);
  253.     } while ( (item != outputAgain) && (item != outputQuit));
  254.     
  255.     DisposeDialog(dlg);
  256.     
  257.     return item;
  258. }
  259.  
  260.  
  261. /*------------------------------------------------------------------------------*\
  262.     initializeData()
  263.  *------------------------------------------------------------------------------*
  264.         initialize data stucture to be passed to CustomPutFile
  265.         this means alocating a pointer of the right size and filling 
  266.         in the suffix strings from the apps resource fork 
  267. \*------------------------------------------------------------------------------*/
  268. void initializeData ( myDataPtr *dataPtr, StandardFileReply *replyPtr )
  269. {
  270.     short    i=0, num=0;
  271.     Str255    temp;
  272.     
  273.     do                                                /* figure out how many suffixes */ 
  274.     {                                                /* are in the apps resource fork */
  275.         GetIndString( temp, SuffixID, num+1);
  276.         num++;
  277.     } while (temp[0] !=0);                            /* if temp[0]==0 then no more */
  278.     num--;                                            /* counted 1 too many so decrement */
  279.     
  280.                                                     /* allocate myDataPtr stucture */
  281.     *dataPtr = (myDataPtr) NewPtrClear ( offsetof(myData,files[num]) );
  282.     
  283.     (**dataPtr).replyPtr = replyPtr;                /* fill in StandardFileReply ptr */ 
  284.     (**dataPtr).num = num;                            /* fill in num of suffixes */ 
  285.  
  286.     for (i=0; i<num; i++)                            /* fill in suffix strings */
  287.            GetIndString( (**dataPtr).files[i].suffix, SuffixID, i+1);
  288. }
  289.  
  290.  
  291. /*------------------------------------------------------------------------------*\
  292.     main()
  293.  *------------------------------------------------------------------------------*
  294.         initialize mamagers and the keep doing 
  295.         CustomPutFile until the user has had enough
  296.         the structure 'dataPtr' is passed to CustomPutFile() so that 
  297.         MyDlgHook() can access the list of suffixes and return the results 
  298. \*------------------------------------------------------------------------------*/
  299. void main ( void )
  300. {
  301.     myDataPtr            dataPtr;
  302.     StandardFileReply    reply;
  303.     Point                where = {-1,-1};            /* center dialog on main screen */
  304.     
  305.     InitToolBox(2);
  306.     
  307.     initializeData (&dataPtr, &reply);
  308.     
  309.     do
  310.     {
  311.         CustomPutFile(    "\pSave files as:",            /* the prompt string */
  312.                         "\pUntitled",                /* the default filename */
  313.                         &reply,                        /* the StandardFileReply structure */
  314.                         0,                            /* the default dialog */
  315.                         where,                        /* position of dialog on screen */
  316.                         (DlgHookYDProcPtr)MyDlgHook,/* the Dialog Hook procedure */
  317.                         nil,                        /* no modal dialog filterProc */
  318.                         nil,                        /* no activeListPtr */
  319.                         nil,                        /* no activateProc */
  320.                         dataPtr                        /* pass in myDataPtr struct so that */
  321.                       );                            /* dlgHook() can access its contents */
  322.     }                                                            
  323.     while (outputDlog(dataPtr)==outputAgain);        /* repeat until user has had enough */
  324.     
  325.     DisposePtr( (Ptr)dataPtr);
  326. }
  327.  
  328.  
  329.